/*
 * Copyright 2007-2008 Andrew O'Malley
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package ws.quokka.plugin.resources;

import org.apache.tools.ant.taskdefs.Copy;
import org.apache.tools.ant.taskdefs.Expand;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.PatternSet;

import ws.quokka.core.metadata.Metadata;
import ws.quokka.core.metadata.MetadataAware;
import ws.quokka.core.repo_spi.RepoArtifact;

import ws.quokka.plugin.lifecycle.LifeCycleImpl;

import java.io.File;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;


/**
 *
 */
public class ResourcesPlugin extends LifeCycleImpl implements MetadataAware {
    //~ Static fields/initializers -------------------------------------------------------------------------------------

    private static final String OUTPUT = "output";
    private static final String INCLUDE_GENERATED_RESOURCES = "includeGeneratedResources";
    private static final String FILTERED = "filtered";
    private static final String FILTERS = "filters";
    private static final String UNFILTERED = "unfiltered";

    //~ Instance fields ------------------------------------------------------------------------------------------------

    private Metadata metadata;

    //~ Methods --------------------------------------------------------------------------------------------------------

    public void setMetadata(Metadata metadata) {
        this.metadata = metadata;
    }

    public void extract() {
        List path = metadata.getProjectPath(properties().getString("artifactPath"));

        assertTrue(path.size() == 1,
            getResources().getPrefix()
            + ".artifactPath must refer to the id of a project path containing a single artifact");

        RepoArtifact artifact = (RepoArtifact)path.get(0);

        // Root dir for resources
        String root = properties().getString("resources.set.dir");

        if (!root.startsWith("/")) {
            root = "/META-INF/quokka/" + artifact.getId().toPathString() + "/" + root;
        }

        // Expand the .jar file
        File dir = artifact.getLocalCopy();

        if (dir.isFile()) {
            Expand expand = (Expand)utils().init(new Expand(), "unjar");
            expand.setSrc(artifact.getLocalCopy());

            PatternSet patternSet = new PatternSet();
            PatternSet.NameEntry entry = patternSet.createInclude();
            entry.setName(root.substring(1) + "/**");
            expand.addPatternset(patternSet);

            // TODO: Eliminate expanding to a temporary dir
            // The code below removes the root properly, however includes and excludes need fixing as well
            //            final String root1 = root;
            //            expand.add(new FileNameMapper() {
            //                public void setFrom(String from) {
            //                }
            //
            //                public void setTo(String to) {
            //                }
            //
            //                public String[] mapFileName(String sourceFileName) {
            //                    return new String[] {sourceFileName.substring(root1.length())};
            //                }
            //            });
            dir = utils().normalise(getTargetDir().getAbsolutePath() + "/temp/extract/" + getResources().getPrefix());
            expand.setDest(dir);
            expand.perform();
        }

        // Override the fileset directory to make it relative to the expanded artifact
        // If dir specified has a leading /, use the supplied value otherwise prefix with the artifact resources dir
        FileSet resources = properties().getFileSet("resources");
        resources.setDir(utils().normalise(dir.getAbsolutePath() + root));

        Copy copy = (Copy)utils().init(new Copy(), "copy");
        copy.setTodir(properties().getFile("toDir"));
        copy.addFileset(resources);
        copy.perform();
    }

    public void process() {
        processResources(getLifeCycle().getState().getFilteredResources(),
            getLifeCycle().getState().getUnfilteredResources(), properties().getFile(OUTPUT));
    }

    public void processTest() {
        processResources(getLifeCycle().getState().getFilteredTestResources(),
            getLifeCycle().getState().getUnfilteredTestResources(), properties().getFile(OUTPUT));
    }

    private void processResources(List filteredResources, List unfilteredResources, File output) {
        boolean includeGenerated = properties().getBoolean(INCLUDE_GENERATED_RESOURCES, false);

        // Copy filtered resources
        log().verbose("Copying filtered resources");
        filteredResources = new ArrayList(includeGenerated ? filteredResources : Collections.EMPTY_LIST);
        filteredResources.addAll(properties().getMap(FILTERED, false, FileSet.class).values());
        copyResources(filteredResources, output, properties().getMap(FILTERS, false, FileSet.class).values());

        // Copy unfiltered resources
        log().verbose("Copying unfiltered resources");
        unfilteredResources = new ArrayList(includeGenerated ? unfilteredResources : Collections.EMPTY_LIST);
        unfilteredResources.addAll(properties().getMap(UNFILTERED, false, FileSet.class).values());
        copyResources(unfilteredResources, output, null);
    }

    private void copyResources(Collection resources, File output, Collection filters) {
        File tokensFile = utils().normalise(getTargetDir().getAbsolutePath() + "/temp/" + getShortTargetName() + "/"
                + ((filters == null) ? FILTERED : UNFILTERED) + ".properties");
        String prefix = properties().getString("ignoredTokensPrefix", "quokka.resources.");
        boolean addProperties = properties().getBoolean("addPropertiesAsTokens", true);

        new ResourcesCopier(getProject(), log()).copy(resources, output, filters, tokensFile, prefix, addProperties);
    }
}
